package com.netty.clientserver.handler;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.netty.clientserver.command.Command;
import com.netty.clientserver.packet.base.Packet;
import com.netty.clientserver.packet.bo.RegisterBo;
import com.netty.clientserver.strategy.factory.TypeStrategyFactory;
import com.netty.clientserver.util.ConnectUtils;
import com.netty.clientserver.util.TokenUtil;
import com.netty.common.constant.Constants;
import com.netty.common.entity.User;
import com.netty.common.entity.vo.LoginUser;
import com.netty.common.enums.ExceptionEnum;
import com.sun.xml.bind.v2.runtime.reflect.Lister;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.handler.codec.json.JsonObjectDecoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**接收/处理/响应客户端websocket请求的业务核心处理类
 * 模板设计，子类重写某些类  SimpleChannelInboundHandler是一个模板类
 * @author LiuXiaoYu
 * @date 2022/2/3- 11:25
 */
@ChannelHandler.Sharable
@Service
@Slf4j
public class MyWebSocketHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

    @Autowired
    private TokenUtil tokenUtil;

    @Autowired
    private TypeStrategyFactory typeStrategyFactory;
    /**
     * 读取客户端传送的消息
     * 模板方法
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {
          handleSocketFrame(ctx,msg);
    }

    /**
     * 处理客户端传送的消息
     * @param ctx
     * @param frame
     */
    private void handleSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
        //首先判断是不是WebSocket关闭操作
        if (frame instanceof CloseWebSocketFrame){
            ctx.channel().close();
        }
        //判断是否ping消息
        if (frame instanceof PingWebSocketFrame){
            ctx.writeAndFlush(new PongWebSocketFrame(frame.content().retain()));
        }

        //转换为文本消息类型
        assert frame instanceof TextWebSocketFrame;
        TextWebSocketFrame textWebSocketFrame=(TextWebSocketFrame)frame;
        //获取内容
        ByteBuf byteBuf = textWebSocketFrame.content();
        //转换为string->json
        String content = byteBuf.toString(StandardCharsets.UTF_8);
        JSONObject jsonObject= JSONObject.parseObject(content);
        Integer type = (Integer) jsonObject.get(Constants.TYPE);
        //根据类型判断执行 switch->策略模式
        Packet packet = typeStrategyFactory.doExecute(ctx.channel(),type.toString(),content);
        // 将自己在私聊或者群聊时说的话返回回去
        if(type.equals(Command.SINGLE_MESSAGE) || type.equals(Command.GROUP_MESSAGE)){
            ByteBuf buf = ConnectUtils.getByteBuf(ctx,packet.getMessage(),packet.getOwnerImage());
            TextWebSocketFrame tws = new TextWebSocketFrame(buf);
            ctx.writeAndFlush(tws);
        }
        //传给下一个handler处理器
        ctx.fireChannelRead(packet);

    }

    /**
     * 户端与服务端创建连接
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ConnectUtils.add(ctx.channel());
        System.out.println("客户端与服务端连接开启");
    }

    /**
     * 客户端与服务端断开连接
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        ConnectUtils.remove(ctx.channel());
        System.out.println("客户端与服务端断开连接连接前开始打印日志->>>>>>>>>>>>>");
        ConnectUtils.print();
        System.out.println("客户端与服务端连接已经关闭了->>>>>>>>>>>>>");
    }

    /**
     * 接收结束之后 read相对于服务端
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    /**
     *  出现异常时调用
     * @param ctx
     * @param cause
     * @throws Exception
     */
//    @Override
//    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//        cause.printStackTrace();
//        ctx.close();
//    }

}
